package text;

import javax.swing.JEditorPane;
import javax.swing.text.Element;
import javax.swing.text.JTextComponent;
import javax.swing.text.ParagraphView;

/**
 * Represents multipage paragraph.
 * 
 * @author Stanislav Lapitsky
 * @version 1.0
 */
class PageableParagraphView extends ParagraphView implements MultiPageView {
	
	private final PageableEditorKit editorKit;

	protected int additionalSpace = 0;
	protected int breakSpan = 0;
	protected int pageOffset = 0;
	protected int startPageNumber = 0;
	protected int endPageNumber = 0;

	public PageableParagraphView(PageableEditorKit editorKit, Element elem) {
		super(elem);
		this.editorKit = editorKit;
	}

	public void layout(int width, int height) {
		super.layout(width, height);
	}

	protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets,
			int[] spans) {
		super.layoutMajorAxis(targetSpan, axis, offsets, spans);
		performMultiPageLayout(targetSpan, axis, offsets, spans);
	}

	/**
	 * Layout paragraph's content splitting between pages if needed. Calculates
	 * shifts and breaks for parent view (SectionView)
	 * 
	 * @param targetSpan
	 *            int
	 * @param axis
	 *            int
	 * @param offsets
	 *            int[]
	 * @param spans
	 *            int[]
	 */
	public void performMultiPageLayout(int targetSpan, int axis, int[] offsets,
			int[] spans) {
		if (breakSpan == 0)
			return;
		int space = breakSpan;

		additionalSpace = 0;
		endPageNumber = startPageNumber;
		int topInset = this.getTopInset();
		int offs = 0;
		int headerHeight = getHeaderHeight();
		int footerHeight = getFooterHeight();
		for (int i = 0; i < offsets.length; i++) {
			if (offs + spans[i] + topInset > space) {
				int newOffset = endPageNumber * editorKit.pageHeight;
				int addSpace = newOffset - (startPageNumber - 1) * editorKit.pageHeight
						- pageOffset - offs - topInset - headerHeight;
				additionalSpace += addSpace;
				offs += addSpace;
				for (int j = i; j < offsets.length; j++) {
					offsets[j] += addSpace;
				}
				endPageNumber++;
				space = (endPageNumber * editorKit.pageHeight - 2 * PageableEditorKit.DRAW_PAGE_INSET
						- editorKit.pageMargins.top - editorKit.pageMargins.bottom)
						- (startPageNumber - 1)
						* editorKit.pageHeight
						- pageOffset
						- footerHeight;
			}
			offs += spans[i];
		}
	}

	protected int getHeaderHeight() {
		JTextComponent text = (JTextComponent) getContainer();
		if (text != null
				&& text instanceof JEditorPane
				&& ((JEditorPane) text).getEditorKit() instanceof PageableEditorKit) {
			PageableEditorKit kit = (PageableEditorKit) ((JEditorPane) text)
					.getEditorKit();
			if (kit.getHeader() != null) {
				return kit.getHeader().getHeight() + PageableEditorKit.HF_SHIFT;
			}
		}
		return 0;
	}

	protected int getFooterHeight() {
		JTextComponent text = (JTextComponent) getContainer();
		if (text != null
				&& ((JEditorPane) text).getEditorKit() instanceof PageableEditorKit) {
			PageableEditorKit kit = (PageableEditorKit) ((JEditorPane) text)
					.getEditorKit();
			if (kit.getFooter() != null) {
				return kit.getFooter().getHeight() + PageableEditorKit.HF_SHIFT;
			}
		}
		return 0;
	}

	/**
	 * Gets view's start page number
	 * 
	 * @return page number
	 */
	public int getStartPageNumber() {
		return startPageNumber;
	}

	/**
	 * Gets view's end page number
	 * 
	 * @return page number
	 */
	public int getEndPageNumber() {
		return endPageNumber;
	}

	/**
	 * Gets view's extra space (space between pages)
	 * 
	 * @return extra space
	 */
	public int getAdditionalSpace() {
		return additionalSpace;
	}

	/**
	 * Gets view's break span
	 * 
	 * @return break span
	 */
	public int getBreakSpan() {
		return breakSpan;
	}

	/**
	 * Gets view's offsets on the page
	 * 
	 * @return offset
	 */
	public int getPageOffset() {
		return pageOffset;
	}

	/**
	 * Sets view's start page number
	 * 
	 * @param startPageNumber
	 *            page number
	 */
	public void setStartPageNumber(int startPageNumber) {
		this.startPageNumber = startPageNumber;
	}

	/**
	 * Sets view's end page number
	 * 
	 * @param endPageNumber
	 *            page number
	 */
	public void setEndPageNumber(int endPageNumber) {
		this.endPageNumber = endPageNumber;
	}

	/**
	 * Sets extra space (space between pages)
	 * 
	 * @param additionalSpace
	 *            additional space
	 */
	public void setAdditionalSpace(int additionalSpace) {
		this.additionalSpace = additionalSpace;
	}

	/**
	 * Sets view's break span.
	 * 
	 * @param breakSpan
	 *            break span
	 */
	public void setBreakSpan(int breakSpan) {
		this.breakSpan = breakSpan;
	}

	/**
	 * Sets view's offset on the page
	 * 
	 * @param pageOffset
	 *            offset
	 */
	public void setPageOffset(int pageOffset) {
		this.pageOffset = pageOffset;
	}
}